package binexpr

import (
	"gitee.com/zhi/binexpr/executor"
	"gitee.com/zhi/binexpr/parser"
)

// FuncDef is the type of custom function.
type FuncDef = executor.FuncDef

// Scope is the map of variables.
type Scope = executor.ScopeMap

// ScopeMap is the map store of a scope.
type ScopeMap = executor.ScopeMap

// ScopeChain is the linked list of scopes.
type ScopeChain = executor.ScopeChain

// NewScopeChain create a new scope chain.
var NewScopeChain = executor.NewScopeChain

// NewFuncDef create the custom function from the declaration type.
func NewFuncDef[F executor.FuncDecl](fn F) (*FuncDef, error) {
	return executor.NewFuncDef(fn)
}

// MustNewFuncDef create the custom function from the declaration type or panic.
func MustNewFuncDef[F executor.FuncDecl](fn F) *FuncDef {
	return executor.MustNewFuncDef(fn)
}

// Interpreter is the interpreter of the binexpr engine.
type Interpreter struct {
	executor *executor.Executor
}

// InterpreterOption is the option to initialize a interpreter.
type InterpreterOption struct {
	GlobalScope Scope
}

// InterpreterOptionSetter is the type following option setter pattern.
type InterpreterOptionSetter func(opt *InterpreterOption)

// WithScope define a map of custom functions to the interpreter.
func WithScope(scope Scope) InterpreterOptionSetter {
	return func(opt *InterpreterOption) {
		if opt.GlobalScope == nil {
			opt.GlobalScope = scope
		} else {
			for key, value := range scope {
				opt.GlobalScope[key] = value
			}
		}
	}
}

// NewInterpreter create a new interpreter.
func NewInterpreter(optSetters ...InterpreterOptionSetter) *Interpreter {
	var opt InterpreterOption
	for _, optSetter := range optSetters {
		optSetter(&opt)
	}
	return &Interpreter{executor: executor.New(opt.GlobalScope)}
}

// Evaluate the given expression string with the scope.
func (i *Interpreter) Evaluate(exprStr string, scope Scope) (any, error) {
	expr, err := parser.Parse(exprStr)
	if err != nil {
		return nil, err
	}
	return i.executor.Execute(expr, scope)
}
